package com.gagakuai.concurrent.locks;

import java.io.Serializable;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/*
 * @program: settement
 * @description: 可重入锁
 * @author: houhong
 * @create: 2022-11-19 22:41
 */
public class ReentrantLock implements Lock, Serializable {


    private final Sync sync;

    /*
     * 默认是一个非公平锁
     */
    public ReentrantLock() {
        sync = new UnFairSync();
    }

    public ReentrantLock(boolean fair) {

        sync = fair ? new FairSync() : new UnFairSync();

    }

    @Override
    public void lock() {
        //生成一张许可证
        sync.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

        sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return false;
    }

    @Override
    public boolean trylock(long time, TimeUnit timeUnit) {
        return false;
    }

    @Override
    public void unlock() {
        sync.release(1);
    }

    @Override
    public Condition newCondition() {

        return sync.newCondition();
    }

    /*
     * 公平锁：
     * 1：在线程去获取锁的时候，需要先去
     * CHL队列里面判断是否还存在是否还有在排队的线程
     * 如果存在的话，就报错，否则就获取，体现公平性
     * 2：在当前线程是当前锁的获取者的时候，直接累计状态
     * 体现了可重入性
     */
    final static class FairSync extends Sync {

        @Override
        protected boolean tryAcquire(int arg) {
            return fairTryAcquire(arg);
        }
    }

    final static class UnFairSync extends Sync {


    }

    /*
     * 1： 同步队列的实现者，实现了锁的语义
     * <p>
     * 1.1:当permisson（许可证）= 0 的时候，
     * 表示锁空闲，当permisson>0的时候，说明
     * 当前锁被某一个线程所占有，同一个thread
     * 进来的时候,permisson会递增.
     * 只有permisson --> 0 的时候 释放锁
     */
    abstract static class Sync extends AbstactQueuedSychronier {

        private static final long serialVersionUID = -4290619882684672200L;

        /*
         * 获取一次公平锁
         * true: 获取成功。false 获取失败
         */
        final boolean fairTryAcquire(int acquires) {

            //获取申请到的线程
            final Thread current = Thread.currentThread();

            // 当前许可证数量
            int state = getState();
            // 如果锁没有被任何线程占用 状态为 0  同步锁处于空闲状态
            if (state == 0) {
                /*
                 *  在这里的时候 需要去看看队列里面有没有线程在排队，如果有的话 优先排队的线程
                 *  没有就获取锁，设置状态
                 *  这里体现的时候公平性
                 */
                if (!hasQueuedPredecessors()) {

                    if (compareAndSetState(0, acquires)) {
                        //设置当前线程为 exCluexThread
                        setExclusiveOwnerThread(current);
                        return true;
                    }
                }
            } else {
                // 说明锁被占用  这里表示可重入性

                // 如果不等 ，说明不是同一个线程进入获取锁
                if (current != getExclusiveOwnerThread()) {

                    return false;
                }
                // 当代码走到这一步来了，：体现可重入性
                int nextc = state + acquires;

                if (nextc < 0) {

                    throw new Error("Maximum lock count exceeded");
                }
                setState(nextc);
                return true;
            }

            return false;
        }

        @Override
        protected final boolean isHeldExclusively() {
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        /*
         * @param releases
         * @return {@link boolean}
         * @Author houhong
         * @Description //TODO 释放锁
         * @Date 10:20 下午 2022/11/20
         */
        @Override
        protected final boolean tryRelease(int releases) {

            //计算应该剩下的凭证
            int c = getState() - releases;

            //判断当前线程是否是当前锁的持有者，如果不是的化，需要报错
            if (!isHeldExclusively()) {
                throw new IllegalMonitorStateException();
            }

            //在这里为了保证可重入性的特性，在这里，需要保证 AQS的state == 0 就重入了几次，必须删除几次，才能够释放锁
            boolean free = false;

            if (c == 0) {
                free = true;
                // 清除当前锁的持有者
                setExclusiveOwnerThread(null);
            }
            //更新许可证
            setState(c);
            return free;
        }


        /*
         *  返回一个条件（条件对象）实列
         */
        final ConditionObject newCondition(){
            return  new ConditionObject();
        }

































    }

}